package com.coocaa.ops.admin.v1.upload.util;

import com.coocaa.ops.admin.v1.upload.ftp.model.ProgressMonitor;
import com.coocaa.ops.admin.v1.upload.properties.UploadProperties;
import com.coocaa.ops.admin.v1.upload.enums.UploadCategoryEnums;
import com.coocaa.ops.admin.v1.upload.exception.FtpException;
import com.coocaa.ops.admin.v1.upload.ftp.MyFtpTemplate;
import com.coocaa.ops.admin.v1.upload.model.ImgUploadResult;
import com.coocaa.ops.admin.v1.upload.model.UploadResult;
import com.coocaa.ops.common.tool.base.InstanceUtil;
import com.coocaa.ops.common.tool.date.DateUtil;
import com.coocaa.ops.common.tool.math.RandomUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.nio.channels.FileChannel;
import java.util.List;
import java.util.Map;

/**
 * @author bijiahao
 * @date : 2019/2/15.
 * @description: 上传工具类
 */
public final class UploadUtil {

    private UploadUtil() {

    }

    public static List<ImgUploadResult> uploadImage(HttpServletRequest request) {
        // 将 request 转化为 multipartRequest
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        String pathDir = getTempUploadDir();
        // 从 multipartRequest 获取 fileMap
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        List<ImgUploadResult> uploadResultList = InstanceUtil.newArrayList();
        for (Map.Entry<String, MultipartFile> entry : fileMap.entrySet()) {
            // 获取 multipartFile
            MultipartFile multipartFile = entry.getValue();
            //处理文件上传
            ImgUploadResult imgUploadResult = getImgUploadResult(multipartFile, pathDir);
            uploadResultList.add(imgUploadResult);
        }
        return uploadResultList;
    }

    public static List<UploadResult> uploadTempFile(HttpServletRequest request, UploadCategoryEnums uploadCategoryEnums) {
        // 将 request 转化为 multipartRequest
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        String pathDir = getTempUploadDir();
        // 从 multipartRequest 获取 fileMap
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        List<UploadResult> uploadResultList = InstanceUtil.newArrayList();
        for (Map.Entry<String, MultipartFile> entry : fileMap.entrySet()) {
            // 获取 multipartFile
            MultipartFile multipartFile = entry.getValue();
            //处理文件上传
            UploadResult uploadResult = getUploadResult(multipartFile, uploadCategoryEnums, pathDir);
            uploadResultList.add(uploadResult);
        }
        return uploadResultList;
    }


    public static void upload2Ftp(String localFilePath, String remoteFilePath) {
        upload2Ftp(new File(localFilePath), remoteFilePath);
    }

    public static void upload2Ftp(File localFile, String remoteFilePath) {
        if (UploadProperties.Constants.ENABLE_UPLOAD_FTP) {
            MyFtpTemplate myFtpTemplate = new MyFtpTemplate();
            myFtpTemplate.upload(localFile, remoteFilePath, new ProgressMonitor());
        }
    }

    public static void write2FileByChannel(InputStream inputStream, File savedFile) {
        if (!(inputStream instanceof FileInputStream)) {
            throw new RuntimeException("InputStream should be FileInputStream");
        }
        FileInputStream fis = null;
        FileOutputStream fos = null;
        FileChannel fisChannel = null;
        FileChannel fosChannel = null;
        try {
            fis = (FileInputStream) inputStream;
            fos = new FileOutputStream(savedFile);
            fisChannel = fis.getChannel();
            fosChannel = fos.getChannel();
            fisChannel.transferTo(0, fisChannel.size(), fosChannel);
            fosChannel.force(false);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fosChannel != null) {
                try {
                    fosChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fisChannel != null) {
                try {
                    fisChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    public static void write2File(InputStream inputStream, File savedFile) {
        OutputStream output = null;
        try {
            if (!savedFile.getParentFile().exists()) {
                FileUtils.forceMkdir(savedFile.getParentFile());
            }
            output = new FileOutputStream(savedFile);
            IOUtils.copy(inputStream, output);
            output.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static UploadResult getUploadResult(MultipartFile multipartFile, UploadCategoryEnums uploadCategoryEnums, String pathDir) {
        String fileOriginName = multipartFile.getOriginalFilename();
        String extName = FileAnalyzerUtil.getFileExtName(fileOriginName);
        //校验类型
        FileExtNameValidator.valid(extName, uploadCategoryEnums);
        String newName = getNewFileName(extName);
        String tempSavePath = getTempUploadPath(pathDir, uploadCategoryEnums, newName);
        File tempSaveFile = new File(tempSavePath);
        handleMakeDirs(tempSaveFile);
        try {
            multipartFile.transferTo(tempSaveFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String fileMd5 = FileMd5Util.getFileMD5(tempSavePath);
        UploadResult uploadResult = new UploadResult();
        uploadResult.setFileMd5(fileMd5);
        uploadResult.setNewFileName(newName);
        uploadResult.setOriginFileName(FileAnalyzerUtil.getFileNameTrimSuffix(fileOriginName));
        uploadResult.setFileType(extName);
        uploadResult.setFileSize(String.valueOf(multipartFile.getSize()));
        uploadResult.setTempStorePath(tempSavePath);
        return uploadResult;
    }


    private static ImgUploadResult getImgUploadResult(MultipartFile multipartFile, String pathDir) {
        String fileOriginName = multipartFile.getOriginalFilename();
        String extName = FileAnalyzerUtil.getFileExtName(fileOriginName);
        //校验类型
        FileExtNameValidator.validImg(extName);
        String resolution = ImageAnalyzerUtil.getImgResolution(extName, multipartFile);
        String newName = getImgNewName(extName, resolution);
        String tempSavePath = getTempUploadPath(pathDir, UploadCategoryEnums.IMG, newName);
        File tempSaveFile = new File(tempSavePath);
        handleMakeDirs(tempSaveFile);
        try {
            multipartFile.transferTo(tempSaveFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String fileMd5 = FileMd5Util.getFileMD5(tempSavePath);
        ImgUploadResult imgUploadResult = new ImgUploadResult();
        imgUploadResult.setFileMd5(fileMd5);
        imgUploadResult.setResolution(resolution);
        imgUploadResult.setNewFileName(newName);
        imgUploadResult.setOriginFileName(FileAnalyzerUtil.getFileNameTrimSuffix(fileOriginName));
        imgUploadResult.setFileType(extName);
        imgUploadResult.setFileSize(String.valueOf(multipartFile.getSize()));
        //设置url
        imgUploadResult.setTempStorePath(tempSavePath);
        return imgUploadResult;
    }


    /**
     * 获取临时上传目录
     *
     * @return
     */
    public static String getTempUploadDir() {
        StringBuilder pathDir = new StringBuilder();
        pathDir.append(UploadProperties.Constants.TEMP_UPLOAD_DIR)
                .append("/")
                .append(UploadProperties.Constants.ENV_DIR);
        return pathDir.toString().intern();
    }

    /**
     * 获取临时上传路径
     *
     * @param pathDir
     * @param uploadCategoryEnums
     * @param newName
     * @return
     */
    private static String getTempUploadPath(String pathDir, UploadCategoryEnums uploadCategoryEnums, String newName) {
        StringBuilder path = new StringBuilder();
        path.append(pathDir)
                .append("/")
                .append(uploadCategoryEnums.name().toLowerCase())
                .append("/")
                .append(newName);
        return path.toString();

    }

    /**
     * 处理创建目录
     *
     * @param tempSaveFile
     */
    private static void handleMakeDirs(File tempSaveFile) {
        if (!tempSaveFile.getParentFile().exists()) {
            try {
                FileUtils.forceMkdir(tempSaveFile.getParentFile());
            } catch (IOException e) {
                throw new FtpException("请检查【temp.upload.dir】配置参数,配置文件【ftp-upload.properties】！");
            }
        }
    }

    /**
     * 获取新的文件名称-图片
     *
     * @param extName
     * @param resolution
     * @return
     */
    private static String getImgNewName(String extName, String resolution) {
        StringBuilder pathDir = new StringBuilder();
        pathDir.append(DateUtil.getCurrentDateStr("yyyyMMdd"))
                .append("/")
                .append(RandomUtil.getRandomLongStr())
                .append("_")
                .append(resolution)
                .append(extName);
        return pathDir.toString();
    }

    /**
     * 获取新的文件名称
     *
     * @param extName
     * @return
     */
    private static String getNewFileName(String extName) {
        StringBuilder pathDir = new StringBuilder();
        pathDir.append(DateUtil.getCurrentDateStr("yyyyMMdd"))
                .append("/")
                .append(RandomUtil.getRandomLongStr())
                .append(extName);
        return pathDir.toString();
    }


}
